
//#define G_DEBUG
//#include "debug.h"

#include <malloc.h>
#include "SDK/amx/amx.h"
#include "SDK/plugincommon.h"

#include "GeoIP.h"
#include "GeoIPCity.h"


typedef void (*logprintf_t)(const char* format, ...);

static logprintf_t logprintf;
static void **ppPluginData;
extern void *pAMXFunctions;

static GeoIP 	*gi,
		*gi_city;

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports()
{
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load( void **ppData )
{
	pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS];
	logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];

	gi = NULL;
	gi_city = NULL;

	logprintf( "  Plugin mygeoip got loaded. Version: " __DATE__ ",  " __TIME__ );
	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload( )
{
	if(gi)	
		GeoIP_delete(gi);
	if(gi_city)
		GeoIP_delete(gi_city);


	gi = NULL;
	gi_city = NULL;
	logprintf("  Plugin mygeoip got unloaded." );
}


static cell AMX_NATIVE_CALL n_cache( AMX* amx, cell* params )
{
	char *path;
	amx_StrParam(amx, params[1], path);
	
	if(!path) return 0;

	if(gi)
		GeoIP_delete(gi);
	gi = GeoIP_open(path, GEOIP_MEMORY_CACHE);
	if(!gi)
	{
		//throw("Country IP database reading error!");
		return 0;
	}
	return 1;
}


static cell AMX_NATIVE_CALL n_iscached( AMX* amx, cell* params )
{
	return(!!gi);
}

static cell AMX_NATIVE_CALL n_uncache( AMX* amx, cell* params )
{
	if(gi)	
	{
		GeoIP_delete(gi);
		gi = NULL;
		return 1;
	}
	return 0;
}


static cell AMX_NATIVE_CALL n_cache_city( AMX* amx, cell* params )
{
	char *path;
	amx_StrParam(amx, params[1], path);
	
	if(!path) return 0;

	if(gi_city)
		GeoIP_delete(gi_city);
	gi_city = GeoIP_open(path, GEOIP_MEMORY_CACHE);
	if(!gi_city)
	{
		//throw("City IP database reading error!");
		return 0;
	}

	return 1;
}

static cell AMX_NATIVE_CALL n_iscached_city( AMX* amx, cell* params )
{
	return(!!gi_city);
}

static cell AMX_NATIVE_CALL n_uncache_city( AMX* amx, cell* params )
{
	if(gi_city)	
	{
		GeoIP_delete(gi_city);
		gi_city = NULL;
		return 1;
	}
	return 0;
}

// native GetCountryCode(const ipaddress[], country[], size);
static cell AMX_NATIVE_CALL n_GetCountryCode( AMX* amx, cell* params )
{
	char *ipaddress;
	amx_StrParam(amx, params[1], ipaddress);
	if(!gi || !ipaddress) return 0;
	const char *country = GeoIP_country_code_by_addr(gi, ipaddress);
	if(!country)
		return 0;

	cell *dest;
	amx_GetAddr(amx, params[2], &dest);
	amx_SetString(dest, country, 0, 0, params[3]);
	return 1;
}

// native GetCountryCode3(const ipaddress[], country[], size);
static cell AMX_NATIVE_CALL n_GetCountryCode3( AMX* amx, cell* params )
{
	char *ipaddress;
	amx_StrParam(amx, params[1], ipaddress);
	if(!gi || !ipaddress) return 0;
	const char *country = GeoIP_country_code3_by_addr(gi, ipaddress);
	if(!country)
		return 0;

	cell *dest;
	amx_GetAddr(amx, params[2], &dest);
	amx_SetString(dest, country, 0, 0, params[3]);
	return 1;
}

// native GetCountryName(const ipaddress[], country[], size);
static cell AMX_NATIVE_CALL n_GetCountryName( AMX* amx, cell* params )
{
	char *ipaddress;
	amx_StrParam(amx, params[1], ipaddress);
	if(!gi || !ipaddress) return 0;
	const char *country = GeoIP_country_name_by_addr(gi, ipaddress);
	if(!country)
		return 0;

	cell *dest;
	amx_GetAddr(amx, params[2], &dest);
	amx_SetString(dest, country, 0, 0, params[3]);
	return 1;
}

// native GetCityName(const ipaddress[], city[], size = sizeof city);
static cell AMX_NATIVE_CALL n_GetCityName( AMX* amx, cell* params )
{
	char *ipaddress;
	amx_StrParam(amx, params[1], ipaddress);
	if(!gi_city || !ipaddress) return 0;

	GeoIPRecord *gir = GeoIP_record_by_addr(gi_city, ipaddress);
	//PRINT_DEBUG();
	if(!gir || !gir->city)
		return 0;

	//PRINT_DEBUG();

	cell *dest;

	amx_GetAddr(amx, params[2], &dest);
	amx_SetString(dest, gir->city, 0, 0, params[3]);

	//PRINT_DEBUG();

	GeoIPRecord_delete(gir);

	return 1;
}
/**********************************/
// native GetCountryCodeByName(const name[], country[], size);
static cell AMX_NATIVE_CALL n_GetCountryCodeByName( AMX* amx, cell* params )
{
	char *name;
	amx_StrParam(amx, params[1], name);
	if(!gi || !name) return 0;
	const char *country = GeoIP_country_code_by_name(gi, name);
	if(!country)
		return 0;

	cell *dest;
	amx_GetAddr(amx, params[2], &dest);
	amx_SetString(dest, country, 0, 0, params[3]);
	return 1;
}

// native GetCountryCode3ByName(const name[], country[], size);
static cell AMX_NATIVE_CALL n_GetCountryCode3ByName( AMX* amx, cell* params )
{
	char *name;
	amx_StrParam(amx, params[1], name);
	if(!gi || !name) return 0;
	const char *country = GeoIP_country_code3_by_name(gi, name);
	if(!country)
		return 0;

	cell *dest;
	amx_GetAddr(amx, params[2], &dest);
	amx_SetString(dest, country, 0, 0, params[3]);
	return 1;
}

// native GetCountryNameByName(const name[], country[], size);
static cell AMX_NATIVE_CALL n_GetCountryNameByName( AMX* amx, cell* params )
{
	char *name;
	amx_StrParam(amx, params[1], name);
	if(!gi || !name) return 0;
	const char *country = GeoIP_country_name_by_name(gi, name);
	if(!country)
		return 0;

	cell *dest;
	amx_GetAddr(amx, params[2], &dest);
	amx_SetString(dest, country, 0, 0, params[3]);
	return 1;
}

// native GetCityLatitudeByName(const name[], &Float:lat);
static AMX_NATIVE_INFO GeoIPPluginNatives[] =
{
	{ "mygeoip_load",		n_cache },
	{ "mygeoip_unload",		n_uncache },
	{ "mygeoip_isloaded",	n_iscached },

	{ "mygeoip_code2",		n_GetCountryCode },
	{ "mygeoip_code3",		n_GetCountryCode3 },
	{ "mygeoip_country",		n_GetCountryName },
	{ "mygeoip_code2byname",	n_GetCountryCodeByName },
	{ "mygeoip_code3byname",	n_GetCountryCode3ByName },
	{ "mygeoip_countrybyname",	n_GetCountryNameByName },

	{ "mygeoip_city_load",		n_cache_city },
	{ "mygeoip_city_unload",	n_uncache_city },
	{ "mygeoip_city_isloaded",	n_iscached_city },
	{ "mygeoip_city_name",		n_GetCityName },

	{ 0, 0 } 
};

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad( AMX *amx )
{
	return amx_Register( amx, GeoIPPluginNatives, -1 );
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload( AMX *amx )
{
	return AMX_ERR_NONE;
}
